( function( ){

	/**
	 * 词法分析
	 */
	function parse( src ){
		var p = 0;
		var row = 1;
		var col = 0;
		var scol = 0;
		var rst = [ ];
		var stat = "init";
		var buf = "";
		var ch = "";

		src += " ";

		function code( ch ){
			return ch.charCodeAt( 0 );
		}
		function save( content, type ){
			rst[rst.length] = {
				ctnt: content,
				type: type,
				row: row,
				col: scol,
				eq: function teq( type, ctnt ) //用于比较tokens
				{
					return this.type==type&&this.ctnt==ctnt;
				}

			};
			stat = "init";
			buf = "";
		}
		function next( ){
			p++;
			col++;
		}
		function chgl( ){
			row++;
			col = 0;
		}
		function init( tgt ){
			stat = tgt;
			scol = col;
			buf = "";
		}
		function push( c ){
			buf += c;
			next( );
		}

		info( "parse begin" );

		while(p<src.length){
			ch = src.charAt( p );
			/*
			 * first
			 */
			if(stat=="init"){
				//identifier
				if(ch=="_"||code( ch )>=code( "a" )&&code( ch )<=code( "z" )||code( ch )>=code( "A" )&&code( ch )<=code( "Z" )){
					init( "id" );
					push( ch );
				}
				//number
				else if(code( ch )>=code( "1" )&&code( ch )<=code( "9" )){
					init( "num" );
					push( ch );
				}
				else if(ch=="0"){
					init( "num0" );
					push( ch );
				}
				//string
				else if(ch=="\""){
					init( "str" );
					next( );
				}
				//mark
				else if(ch=="{"||ch=="}"||ch=="["||ch=="]"||ch=="("||ch==")"||ch==";"||ch==":"||ch==","||ch=="."||ch=="?"||ch=="+"||ch=="*"||ch=="%"||ch=="~"||ch=="^"){
					scol = col;
					save( ch, "mark" );
					next( );
				}
				else if(ch=="-"){
					init( "mark-" );
					next( );
				}
				else if(ch=="="){
					init( "mark=" );
					next( );
				}
				else if(ch=="!"){
					init( "mark!" );
					next( );
				}
				else if(ch==">"){
					init( "mark>" );
					next( );
				}
				else if(ch=="<"){
					init( "mark<" );
					next( );
				}
				else if(ch=="&"){
					init( "mark&" );
					next( );
				}
				else if(ch=="|"){
					init( "mark|" );
					next( );
				}
				else if(ch=="/"){
					init( "mark/" );
					next( );
				}
				else if(ch=="\n"){
					init( "chgl\\n" );
					next( );
				}
				else if(ch=="\r"){
					init( "chgl\\r" );
					next( );
				}
				//other: treat as blank
				else{
					next( );
				}
			}
			/*
			 * identifier
			 */
			else if(stat=="id"){
				if(ch=="_"||code( ch )>=code( "a" )&&code( ch )<=code( "z" )||code( ch )>=code( "A" )&&code( ch )<=code( "Z" )||code( ch )>=code( "0" )&&code( ch )<=code( "9" )){
					push( ch );
				}
				else{
					save( buf, "id" );
				}
			}
			/*
			 * number
			 */
			else if(stat=="num0"){
				if(code( ch )>=code( "0" )&&code( ch )<=code( "9" )){
					stat = "num";
					push( ch );
				}
				else if(ch=="x"||ch=="X"){
					stat = "numhex";
					push( ch );
				}
				else{
					save( "0", "num" );
				}
			}
			else if(stat=="num"){
				if(code( ch )>=code( "0" )&&code( ch )<=code( "9" )){
					push( ch );
				}
				else{
					save( buf, "num" );
				}
			}
			else if(stat=="numhex"){
				if(code( ch )>=code( "a" )&&code( ch )<=code( "f" )||code( ch )>=code( "A" )&&code( ch )<=code( "F" )||code( ch )>=code( "0" )&&code( ch )<=code( "9" )){
					push( ch );
				}
				else{
					save( buf, "num" );
				}
			}
			/*
			 * string
			 */
			else if(stat=="str"){
				if(ch=="\\"){
					stat = "str\\";
					next( );
				}
				else if(ch=="\""){
					save( buf, "str" );
					next( );
				}
				else{
					push( ch );
				}
			}
			else if(stat=="str\\"){
				if(ch=="\\"){
					stat = "str";
					push( "\\" );
				}
				else if(ch=="\""){
					stat = "str";
					push( "\"" );
				}
				else if(ch=="a"){
					stat = "str";
					push( "\a" );
				}
				else if(ch=="b"){
					stat = "str";
					push( "\b" );
				}
				else if(ch=="f"){
					stat = "str";
					push( "\f" );
				}
				else if(ch=="n"){
					stat = "str";
					push( "\n" );
				}
				else if(ch=="r"){
					stat = "str";
					push( "\r" );
				}
				else if(ch=="t"){
					stat = "str";
					push( "\t" );
				}
				else if(ch=="v"){
					stat = "str";
					push( "\v" );
				}
				else{
					stat = "str";
					next( );
				}
			}
			/*
			 * compsite mark
			 */
			else if(stat=="mark-"){
				if(ch==">"){
					save( "->", "mark" );
					next( );
				}
				else{
					save( "-", "mark" );
				}
			}
			else if(stat=="mark="){
				if(ch=="="){
					save( "==", "mark" );
					next( );
				}
				else{
					save( "=", "mark" );
				}
			}
			else if(stat=="mark!"){
				if(ch=="="){
					save( "!=", "mark" );
					next( );
				}
				else{
					save( "!", "mark" );
				}
			}
			else if(stat=="mark&"){
				if(ch=="&"){
					save( "&&", "mark" );
					next( );
				}
				else{
					save( "&", "mark" );
				}
			}
			else if(stat=="mark|"){
				if(ch=="|"){
					save( "||", "mark" );
					next( );
				}
				else{
					save( "|", "mark" );
				}
			}
			else if(stat=="mark>"){
				if(ch==">"){
					save( ">>", "mark" );
					next( );
				}
				else if(ch=="="){
					save( ">=", "mark" );
					next( );
				}
				else{
					save( ">", "mark" );
				}
			}
			else if(stat=="mark<"){
				if(ch=="<"){
					save( "<<", "mark" );
					next( );
				}
				else if(ch=="="){
					save( "<=", "mark" );
					next( );
				}
				else{
					save( "<", "mark" );
				}
			}
			else if(stat=="mark/"){
				if(ch=="/"){
					stat = "coml";
					next( );
				}
				else if(ch=="*"){
					stat = "comb";
					next( );
				}
				else{
					save( "/", "mark" );
				}
			}
			/*
			 * comment
			 */
			else if(stat=="coml"){
				if(ch=="\r"||ch=="\n"){
					stat = "init";
					next( );
				}
				else{
					next( );
				}
			}
			else if(stat=="comb"){
				if(ch=="*"){
					stat = "comb*";
					next( );
				}
				else{
					next( );
				}
			}
			else if(stat=="comb*"){
				if(ch=="/"){
					stat = "init";
					next( );
				}
				else if(ch=="*"){
					next( );
				}
				else{
					stat = "comb";
					next( );
				}
			}
			/*
			 * change line
			 */
			else if(stat=="chgl\\n"){
				if(ch=="\r"){
					stat = "init";
					next( );
					chgl( );
				}
				else{
					stat = "init";
					chgl( );
				}
			}
			else if(stat=="chgl\\r"){
				if(ch=="\n"){
					stat = "init";
					next( );
					chgl( );
				}
				else{
					stat = "init";
					chgl( );
				}
			}
			/*
			 * should not be here
			 */
			else{
				alert( "unknown stat" );
			}
		}

		info( "parse done" );

		return rst;
	}

	/**
	 * 挑出词法词标识符中的关键字
	 */
	function findKeys( tokens ){
		var keys = [ "typedef", "function", "template", "var", "if", "else", "while", "break", "return", "null", "void" ];
		var i = 0;
		for(i in tokens){
			if(tokens[i].type=="id"){
				var j = 0;
				for(j in keys){
					if(tokens[i].ctnt==keys[j]){
						tokens[i].type = "key";
						break;
					}
				}
			}
		}
		return tokens;
	}

	exports.lex = function( src ){
		return findKeys( parse( src ) );
	};

} )( );